package com.plugin;

import com.util.StringUtil;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.config.PropertyRegistry;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

/**
 * 描述：生成服务层代码
 * 作者：刘飞华
 * 日期：2024/7/24 13:46
 */
public class ServiceGenerator extends PluginAdapter {

    private final Properties properties;

    private String author;

    private String createTime;

    @Override
    public boolean validate(List<String> warnings) {
        return true;
    }

    public ServiceGenerator() {
        this.properties = new Properties();
    }

    public ServiceGenerator(Properties properties) {
        this.properties = properties;

    }

    @Override
    public void setProperties(Properties properties) {
        this.properties.putAll(properties);
        this.author = properties.getProperty("author");
        SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        this.createTime = dateFormatter.format(new Date());
    }

    /**
     * 可以生成自定义的文件
     */
    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {
        List<GeneratedJavaFile> javaFiles = new ArrayList<>();
        javaFiles.add(genServiceInterfaceJavaFile(introspectedTable));
        javaFiles.add(genServiceImplJavaFile(introspectedTable));
        return javaFiles;
    }

    /**
     * 生成一个自定义文件
     */
    private GeneratedJavaFile genServiceInterfaceJavaFile(IntrospectedTable introspectedTable) {
        String targetPackage = properties.getProperty("targetPackage");
        String[] split = introspectedTable.getBaseRecordType().split("\\.");
        String modelName = split[split.length - 1];
        String typeName = targetPackage + "." + modelName + "Service";
        //类的完全限定名（决定生成的文件的目录接口）
        Interface c = new Interface(typeName);

        //设置注释
        c.addJavaDocLine("/**");
        String remarks = introspectedTable.getRemarks().replace("表","");
        c.addJavaDocLine(" * 描述: " + remarks);
        c.addJavaDocLine(" * 作者: " + author);
        c.addJavaDocLine(" * 日期: " + createTime);
        c.addJavaDocLine(" */");

        c.setVisibility(JavaVisibility.PUBLIC);



        //导入的依赖包
        String basePackage = targetPackage.replace("service", "");

        c.addImportedType(new FullyQualifiedJavaType("java.util.List"));
        c.addImportedType(new FullyQualifiedJavaType(basePackage + "vo.req.*"));
        c.addImportedType(new FullyQualifiedJavaType(basePackage + "vo.resp.*"));


        //构建一个编译单元
        GeneratedJavaFile generatedJavaFile = new GeneratedJavaFile(
                c,
                context.getJavaModelGeneratorConfiguration().getTargetProject(),
                context.getProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING),
                context.getJavaFormatter());

        //1.添加方法
        Method add = new Method("save" + modelName);
        add.setName("save" + modelName);
        add.setReturnType(FullyQualifiedJavaType.getIntInstance());
        add.addParameter(new Parameter(new FullyQualifiedJavaType("Add"+modelName+"ReqVo"), "record"));
        add.addJavaDocLine("/**");
        add.addJavaDocLine(" * 添加" + remarks);
        add.addJavaDocLine(" *");
        add.addJavaDocLine(" * @param record 请求参数");
        add.addJavaDocLine(" * @return int");
        add.addJavaDocLine(" * @author " + author);
        add.addJavaDocLine(" * @date " + createTime);
        add.addJavaDocLine(" */");
        add.setAbstract(true);
        c.addMethod(add);

        //2.删除方法
        Method del = new Method("delete" + modelName);
        del.setName("delete" + modelName);
        del.setReturnType(FullyQualifiedJavaType.getIntInstance());
        del.addParameter(new Parameter(new FullyQualifiedJavaType("Delete"+modelName+"ReqVo"), "record"));
        del.addJavaDocLine("/**");
        del.addJavaDocLine(" * 删除" + remarks);
        del.addJavaDocLine(" *");
        del.addJavaDocLine(" * @param record 请求参数");
        del.addJavaDocLine(" * @return int");
        del.addJavaDocLine(" * @author " + author);
        del.addJavaDocLine(" * @date " + createTime);
        del.addJavaDocLine(" */");
        del.setAbstract(true);
        c.addMethod(del);

        //3.更新方法
        Method update = new Method("update" + modelName);
        update.setName("update" + modelName);
        update.setReturnType(FullyQualifiedJavaType.getIntInstance());
        update.addParameter(new Parameter(new FullyQualifiedJavaType("Update"+modelName+"ReqVo"), "record"));
        update.addJavaDocLine("/**");
        update.addJavaDocLine(" * 更新" + remarks);
        update.addJavaDocLine(" *");
        update.addJavaDocLine(" * @param record 请求参数");
        update.addJavaDocLine(" * @return int");
        update.addJavaDocLine(" * @author " + author);
        update.addJavaDocLine(" * @date " + createTime);
        update.addJavaDocLine(" */");
        update.setAbstract(true);
        c.addMethod(update);

        //4.更新状态方法
        Method updateStatus = new Method("update" + modelName + "Status");
        updateStatus.setName("update" + modelName + "Status");
        updateStatus.setReturnType(FullyQualifiedJavaType.getIntInstance());
        updateStatus.addParameter(new Parameter(new FullyQualifiedJavaType("Update"+modelName+"StatusReqVo"), "record"));
        updateStatus.addJavaDocLine("/**");
        updateStatus.addJavaDocLine(" * 更新" + remarks + "状态");
        updateStatus.addJavaDocLine(" *");
        updateStatus.addJavaDocLine(" * @param record 请求参数");
        updateStatus.addJavaDocLine(" * @return int");
        updateStatus.addJavaDocLine(" * @author " + author);
        updateStatus.addJavaDocLine(" * @date " + createTime);
        updateStatus.addJavaDocLine(" */");
        updateStatus.setAbstract(true);
        c.addMethod(updateStatus);

        //5.查询详情
        Method query = new Method("query" + modelName + "Detail");
        query.setName("query" + modelName + "Detail");
        query.setReturnType(new FullyQualifiedJavaType("Query"+modelName+"DetailRespVo"));
        query.addParameter(new Parameter(new FullyQualifiedJavaType("Query"+modelName+"DetailReqVo"), "record"));
        query.addJavaDocLine("/**");
        query.addJavaDocLine(" * 查询" + remarks + "详情");
        query.addJavaDocLine(" *");
        query.addJavaDocLine(" * @param record 请求参数");
        query.addJavaDocLine(" * @return Query" + modelName + "DetailRespVo");
        query.addJavaDocLine(" * @author " + author);
        query.addJavaDocLine(" * @date " + createTime);
        query.addJavaDocLine(" */");
        query.setAbstract(true);
        c.addMethod(query);

        //6.查询列表
        Method queryList = new Method("query" + modelName + "List");
        queryList.setName("query" + modelName + "List");
        FullyQualifiedJavaType newArrayListInstance = FullyQualifiedJavaType.getNewListInstance();
        newArrayListInstance.addTypeArgument(new FullyQualifiedJavaType("Query"+modelName+"ListRespVo"));
        queryList.setReturnType(newArrayListInstance);
        queryList.addParameter(new Parameter(new FullyQualifiedJavaType("Query"+modelName+"ListReqVo"), "record"));
        queryList.addJavaDocLine("/**");
        queryList.addJavaDocLine(" * 查询列表" + remarks + "列表");
        queryList.addJavaDocLine(" *");
        queryList.addJavaDocLine(" * @param record 请求参数");
        queryList.addJavaDocLine(" * @return List<Query" + modelName + "ListRespVo>");
        queryList.addJavaDocLine(" * @author " + author);
        queryList.addJavaDocLine(" * @date " + createTime);
        queryList.addJavaDocLine(" */");
        queryList.setAbstract(true);
        c.addMethod(queryList);

        return generatedJavaFile;
    }

    /**
     * 生成一个自定义文件
     */
    private GeneratedJavaFile genServiceImplJavaFile(IntrospectedTable introspectedTable) {
        String targetPackage = properties.getProperty("targetPackage");
        String[] split = introspectedTable.getBaseRecordType().split("\\.");
        String modelName = split[split.length - 1];
        String typeName = targetPackage + ".impl." + modelName + "ServiceImpl";
        //类的完全限定名（决定生成的文件的目录接口）
        TopLevelClass c = new TopLevelClass(typeName);

        //设置注释
        c.addJavaDocLine("/**");
        String remarks = introspectedTable.getRemarks().replace("表","");
        c.addJavaDocLine(" * 描述: " + remarks);
        c.addJavaDocLine(" * 作者: " + author);
        c.addJavaDocLine(" * 日期: " + createTime);
        c.addJavaDocLine(" */");

        c.setVisibility(JavaVisibility.PUBLIC);

        String bizName = StringUtil.firstCharToUpperCase(modelName) + "Biz";
        Field f = new Field(bizName, new FullyQualifiedJavaType(modelName + "Biz"));
        f.setVisibility(JavaVisibility.PRIVATE);
        f.addAnnotation("@Autowired");
        f.setName(bizName);
        f.setType(new FullyQualifiedJavaType(modelName + "Biz"));
        c.addField(f);

        c.addSuperInterface(new FullyQualifiedJavaType(modelName + "Service"));

        c.addAnnotation("@Service");
        //导入的依赖包
        String basePackage = targetPackage.replace("service", "");


        c.addImportedType(new FullyQualifiedJavaType("java.util.List"));
        c.addImportedType(new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()));
        c.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));
        c.addImportedType(new FullyQualifiedJavaType(targetPackage + "." + modelName + "Service"));
        c.addImportedType(new FullyQualifiedJavaType(basePackage + "vo.req.*"));
        c.addImportedType(new FullyQualifiedJavaType(basePackage + "vo.resp.*"));
        c.addImportedType(new FullyQualifiedJavaType(basePackage + "biz." + modelName + "Biz"));
        c.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));

        //构建一个编译单元
        GeneratedJavaFile generatedJavaFile = new GeneratedJavaFile(
                c,
                context.getJavaModelGeneratorConfiguration().getTargetProject(),
                context.getProperty(PropertyRegistry.CONTEXT_JAVA_FILE_ENCODING),
                context.getJavaFormatter());

        //1.添加方法
        Method add = new Method("save" + modelName);
        add.setName("save" + modelName);
        add.setVisibility(JavaVisibility.PUBLIC);
        add.setReturnType(FullyQualifiedJavaType.getIntInstance());
        add.addParameter(new Parameter(new FullyQualifiedJavaType("Add"+modelName+"ReqVo"), "record"));add.addJavaDocLine("/**");
        add.addJavaDocLine(" * 添加" + remarks);
        add.addJavaDocLine(" *");
        add.addJavaDocLine(" * @param record 请求参数");
        add.addJavaDocLine(" * @return int");
        add.addJavaDocLine(" * @author " + author);
        add.addJavaDocLine(" * @date " + createTime);
        add.addJavaDocLine(" */");
        add.addAnnotation("@Override");

        add.addBodyLine("return " + bizName + ".save" + modelName + "(record);");
        c.addMethod(add);

        //2.删除方法
        Method del = new Method("delete" + modelName);
        del.setName("delete" + modelName);
        del.setVisibility(JavaVisibility.PUBLIC);
        del.setReturnType(FullyQualifiedJavaType.getIntInstance());
        del.addParameter(new Parameter(new FullyQualifiedJavaType("Delete"+modelName+"ReqVo"), "record"));
        del.addJavaDocLine("/**");
        del.addJavaDocLine(" * 删除" + remarks);
        del.addJavaDocLine(" *");
        del.addJavaDocLine(" * @param record 请求参数");
        del.addJavaDocLine(" * @return int");
        del.addJavaDocLine(" * @author " + author);
        del.addJavaDocLine(" * @date " + createTime);
        del.addJavaDocLine(" */");
        del.addAnnotation("@Override");

        del.addBodyLine("return " + bizName + ".delete" + modelName + "(record);");
        c.addMethod(del);

        //3.更新方法
        Method update = new Method("update" + modelName);
        update.setName("update" + modelName);
        update.setVisibility(JavaVisibility.PUBLIC);
        update.setReturnType(FullyQualifiedJavaType.getIntInstance());
        update.addParameter(new Parameter(new FullyQualifiedJavaType("Update"+modelName+"ReqVo"), "record"));
        update.addJavaDocLine("/**");
        update.addJavaDocLine(" * 更新" + remarks);
        update.addJavaDocLine(" *");
        update.addJavaDocLine(" * @param record 请求参数");
        update.addJavaDocLine(" * @return int");
        update.addJavaDocLine(" * @author " + author);
        update.addJavaDocLine(" * @date " + createTime);
        update.addJavaDocLine(" */");
        update.addAnnotation("@Override");

        update.addBodyLine("return " + bizName + ".update" + modelName + "(record);");
        c.addMethod(update);

        //4.更新状态方法
        Method updateStatus = new Method("update" + modelName + "Status");
        updateStatus.setName("update" + modelName + "Status");
        updateStatus.setVisibility(JavaVisibility.PUBLIC);
        updateStatus.setReturnType(FullyQualifiedJavaType.getIntInstance());
        updateStatus.addParameter(new Parameter(new FullyQualifiedJavaType("Update"+modelName+"StatusReqVo"), "record"));
        updateStatus.addJavaDocLine("/**");
        updateStatus.addJavaDocLine(" * 更新" + remarks + "状态");
        updateStatus.addJavaDocLine(" *");
        updateStatus.addJavaDocLine(" * @param record 请求参数");
        updateStatus.addJavaDocLine(" * @return int");
        updateStatus.addJavaDocLine(" * @author " + author);
        updateStatus.addJavaDocLine(" * @date " + createTime);
        updateStatus.addJavaDocLine(" */");
        updateStatus.addAnnotation("@Override");

        updateStatus.addBodyLine("return " + bizName + ".update" + modelName + "Status(record);");
        c.addMethod(updateStatus);

        //5.查询详情
        Method query = new Method("query" + modelName + "Detail");
        query.setName("query" + modelName + "Detail");
        query.setVisibility(JavaVisibility.PUBLIC);
        query.setReturnType(new FullyQualifiedJavaType("Query"+modelName+"DetailRespVo"));
        query.addParameter(new Parameter(new FullyQualifiedJavaType("Query"+modelName+"DetailReqVo"), "record"));
        query.addJavaDocLine("/**");
        query.addJavaDocLine(" * 查询" + remarks + "详情");
        query.addJavaDocLine(" *");
        query.addJavaDocLine(" * @param record 请求参数");
        query.addJavaDocLine(" * @return Query" + modelName + "DetailRespVo");
        query.addJavaDocLine(" * @author " + author);
        query.addJavaDocLine(" * @date " + createTime);
        query.addJavaDocLine(" */");
        query.addAnnotation("@Override");

        query.addBodyLine("return " + bizName + ".query" + modelName + "Detail(record);");
        c.addMethod(query);

        //6.查询列表
        Method queryList = new Method("query" + modelName + "List");
        queryList.setName("query" + modelName + "List");
        queryList.setVisibility(JavaVisibility.PUBLIC);
        FullyQualifiedJavaType newArrayListInstance = FullyQualifiedJavaType.getNewListInstance();
        newArrayListInstance.addTypeArgument(new FullyQualifiedJavaType("Query"+modelName+"ListRespVo"));
        queryList.setReturnType(newArrayListInstance);
        queryList.addParameter(new Parameter(new FullyQualifiedJavaType("Query"+modelName+"ListReqVo"), "record"));
        queryList.addJavaDocLine("/**");
        queryList.addJavaDocLine(" * 查询列表" + remarks + "列表");
        queryList.addJavaDocLine(" *");
        queryList.addJavaDocLine(" * @param record 请求参数");
        queryList.addJavaDocLine(" * @return List<Query" + modelName + "ListRespVo>");
        queryList.addJavaDocLine(" * @author " + author);
        queryList.addJavaDocLine(" * @date " + createTime);
        queryList.addJavaDocLine(" */");
        queryList.addAnnotation("@Override");

        queryList.addBodyLine("return " + bizName + ".query" + modelName + "List(record);");
        c.addMethod(queryList);

        return generatedJavaFile;
    }
}
